package sinhalatransliterartor;

import Dictionary.Data;
import com.sun.star.frame.XController;
import com.sun.star.frame.XDesktop;
import com.sun.star.frame.XModel;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.text.XText;
import com.sun.star.text.XTextCursor;
import com.sun.star.text.XTextViewCursor;
import com.sun.star.text.XTextViewCursorSupplier;
import com.sun.star.uno.Exception;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.BadLocationException;

/**
 * This class creates a GUI for the Transliteration System.
 * It has a text area where user can enter text in English and it is
 * transliterated back to Sinhala.
 * @author SUMEDHA
 */
public class TransliterationUI extends javax.swing.JFrame {

    //A Transliterator object which has the algorithm of transliteration.
    Transliterator transliterator;
    //Path to the Image of Character Map
    private String path;
    //To access objects of Open Office
    private XComponentContext m_xContext;
    private XText xText;
    private XTextViewCursor xViewCursor;
    private XTextCursor xTextCursor;
    //Variables to keep Strings needed
    private String trnsWord;
    private String word = "";
    private String displayWord = "";
    //Variables to keep the details about the string which is being transliterated.
    private int charCount = 0;
    private int spaceCount = 0;
    private int preSpaceCount;
    private char preKeyChar;

    /**
     * Creates a new Form of Transliteration UI
     * @param path  The path to the location of the Character Map image which is a String
     * @param context   XComponentContext Object
     */
    public TransliterationUI(String path, XComponentContext context) {
        try {
            //To get file name of the Image
            Data data = new Data();
            //Setting the complete path
            this.path = path + data.getImageLocation();
            this.m_xContext = context;
            //Setting the System Look and Feel
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            initComponents();
            //Initailizing Components to access Open Office environment
            initializeComponents();
            //Placing the GUI in the bottom of the window
            setBottomLocation();
            jTextArea1.setLineWrap(true);
            //Creating a Transliterator object which has the algorithm of transliteration.
            transliterator = new Transliterator();
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(TransliterationUI.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Logger.getLogger(TransliterationUI.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(TransliterationUI.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedLookAndFeelException ex) {
            Logger.getLogger(TransliterationUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        jTextArea1 = new javax.swing.JTextArea();
        okButton = new javax.swing.JButton();
        cancelButton = new javax.swing.JButton();
        keyMapButton = new javax.swing.JButton();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Transliterator");
        setResizable(false);

        jTextArea1.setColumns(20);
        jTextArea1.setFont(new java.awt.Font("Iskoola Pota", 0, 18)); // NOI18N
        jTextArea1.setRows(5);
        jTextArea1.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                jTextArea1KeyReleased(evt);
            }
            public void keyTyped(java.awt.event.KeyEvent evt) {
                jTextArea1KeyTyped(evt);
            }
        });
        jScrollPane1.setViewportView(jTextArea1);

        okButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/sinhalatransliterartor/Images/stock_check_filled.png"))); // NOI18N
        okButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                okButtonActionPerformed(evt);
            }
        });

        cancelButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/sinhalatransliterartor/Images/cancel.png"))); // NOI18N
        cancelButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelButtonActionPerformed(evt);
            }
        });

        keyMapButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/sinhalatransliterartor/Images/accessories_character_map.png"))); // NOI18N
        keyMapButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                keyMapButtonActionPerformed(evt);
            }
        });

        jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/sinhalatransliterartor/Images/openoffice-logo-small.jpg"))); // NOI18N

        jLabel2.setFont(new java.awt.Font("Microsoft Sans Serif", 0, 18)); // NOI18N
        jLabel2.setText("Enter Text Here");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 538, Short.MAX_VALUE))
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(jLabel1)
                        .addGap(57, 57, 57)
                        .addComponent(okButton)
                        .addGap(18, 18, 18)
                        .addComponent(keyMapButton)
                        .addGap(18, 18, 18)
                        .addComponent(cancelButton))
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 173, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 111, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel1)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(23, 23, 23)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(cancelButton)
                            .addComponent(keyMapButton)
                            .addComponent(okButton))))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    /**
     * When a key is released this method checks which key is released
     * and if the space key is released it transliterate the word which has been
     * entered prior to the space.
     * @param evt
     */
    private void jTextArea1KeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextArea1KeyReleased
        //Check for the Space key release
        if (evt.getKeyChar() == KeyEvent.VK_SPACE) {
            //Counting the total characters entered
            charCount++;
            /**
             * Transliteration of the word. If their is an alternation it is also
             * appended to the word accordingly.
             */
            trnsWord = displayWord + transliterator.transliterate(word);
            //Appends the newly transliterated word to the text
            jTextArea1.replaceRange(trnsWord, spaceCount, charCount - 1);
            //Cleares the word variable which is used to construct a word
            word = "";
             //Setting the previous space psoition
            preSpaceCount = spaceCount;
            //Getting the new space position
            spaceCount = jTextArea1.getText().length();
            //Setting the new length
            charCount = spaceCount;
            //Cleares the variable used in alternation
            displayWord = "";
            //Sets the previous key character as space
            preKeyChar = KeyEvent.VK_SPACE;
        }
    }//GEN-LAST:event_jTextArea1KeyReleased

    /**
     *  This method shows the Key Map. Path is generated when the extension initialize
     * (When reading the data bases) and it is used to access the image containing the map
     * @param evt
     */
    private void keyMapButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keyMapButtonActionPerformed

        ShowMap showMap = new ShowMap(getPath());
        showMap.showKeyMap(getPath());
    }//GEN-LAST:event_keyMapButtonActionPerformed

    /**
     * When OK button is pressed the text which has been transliterated
     * will be entered in to Open Office by insertText() method
     * @param evt
     */
    private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed

        try {
            String text = jTextArea1.getText();
            insertText(text);
            jTextArea1.setText("");
            charCount = 0;
            spaceCount = 0;
            preSpaceCount = 0;
            word = displayWord = "";
        } catch (Exception ex) {
            Logger.getLogger(TransliterationUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }//GEN-LAST:event_okButtonActionPerformed

    /**
     * When the cancel button is clicked the frame is disposed.
     * @param evt
     */
    private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
        this.dispose();
    }//GEN-LAST:event_cancelButtonActionPerformed

    /**
     * This method is called when a key is typed. If the key is an alpha numeric
     * key a word is formed using the input character and the previous characters.
     * Alternation of the previously transliterated or entered text is detected
     * by use of Back space, Delete or arrow keys.
     * Variables spaceCount and preSpaceCount is used to determine the positions
     * of spaces in the text
     * @param evt
     */
    private void jTextArea1KeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextArea1KeyTyped
        //To determine if their is an alteration of the previously transliterated or entered text
        if (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE || evt.getKeyChar() == KeyEvent.VK_DELETE
                || evt.getKeyChar() == KeyEvent.VK_RIGHT || evt.getKeyChar() == KeyEvent.VK_LEFT) {
            /**
             * If there is an alteration which is of only one or two words, only
             * those words will be replaced. For every alternation of the word the
             * the part which is not altered is captured and when making the final
             * word it is used.
             */
            if (jTextArea1.getText().length() >= preSpaceCount) {
                /**
                 * If the word being altered is previous word to the current word.
                 * That is after pressing of space and then alter the word which
                 * is transliterated before.
                 */
                if (preKeyChar == KeyEvent.VK_SPACE) {
                    try {
                        //Getting the new lenngth of the text
                        charCount = jTextArea1.getText().length();
                        //Setting the new spaceCount
                        spaceCount = preSpaceCount;
                        //Getting the length of the word to be replaced
                        int length = charCount - preSpaceCount;
                        //getting the word that is altered
                        displayWord = jTextArea1.getText(preSpaceCount, length);
                    } catch (BadLocationException ex) {
                        Logger.getLogger(TransliterationUI.class.getName()).log(Level.SEVERE, null, ex);
                    }

                } /**
                 * If the word being altered is the current word, remaining part of the current
                 * word is obtained.
                 */
                else {
                    try {
                        //Getting the new lenngth of the text
                        charCount = jTextArea1.getText().length();
                        //getting the word that is altered
                        word = jTextArea1.getText(spaceCount, charCount - spaceCount);
                    } catch (BadLocationException ex) {
                        Logger.getLogger(TransliterationUI.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }

            } /**
             * If their is an alteration of more than two words, the text which is
             * in the text box after the alteration is obtained and variables used
             * in transliteration is reseted. So transliteration will start
             * again with the new word and the text obtained is appended in front of that word.
             */
            else {
                //Obtaining the text which has been transliterated
                String text = jTextArea1.getText();
                //Reseting the variables
                reset();
                //Appending the text obtaied
                jTextArea1.setText(text);
            }
        } /**
         * In the case of an alphanumeric key being pressed, the word is constructed 
         * using the key values and it will be transliterated when the space key is pressed
         */
        else {
            //Keepin rack of the no of charaters
            charCount++;
            //Contructing the word using the input character
            word = word + evt.getKeyChar();
            preKeyChar = evt.getKeyChar();
        }          // TODO add your handling code here:
    }//GEN-LAST:event_jTextArea1KeyTyped
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton cancelButton;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea jTextArea1;
    private javax.swing.JButton keyMapButton;
    private javax.swing.JButton okButton;
    // End of variables declaration//GEN-END:variables


    /**
     * This method inserts a text(String) to  an Open Office Document. It inserts
     * the text to the position where the cursor is.
     * @param text the text to be inserted
     * @throws com.sun.star.uno.Exception
     */
    protected void insertText(String text) throws com.sun.star.uno.Exception {
        xText = xViewCursor.getText();
        // the text creates a model cursor from the viewcursor
        xTextCursor = xText.createTextCursorByRange(xViewCursor.getStart());
        // inserts the text
        xText.insertString(xTextCursor, text, true);
    }

    /**
     * This method initialize the components that are used to access the environment
     * of Open Office. They are used to insert text into the document
     */
    private void initializeComponents() {
        try {
            // create new writer document and get text, then manipulate text
            // Get the remote office service manager
            XMultiComponentFactory xmcf = m_xContext.getServiceManager();
            // get the Desktop service
            Object desktop = xmcf.createInstanceWithContext("com.sun.star." + "frame.Desktop", m_xContext);
            // query its XDesktop interface, we need the current component
            XDesktop xDesktop = (XDesktop) UnoRuntime.queryInterface(XDesktop.class, desktop);
            // retrieve the current component and access the controller
            XComponent xCurrentComponent = xDesktop.getCurrentComponent();
            // get the XModel interface from the component
            XModel xModel = (XModel) UnoRuntime.queryInterface(XModel.class, xCurrentComponent);
            // the model knows its controller
            XController xController = xModel.getCurrentController();
            // the controller gives us the TextViewCursor
            // query the viewcursor supplier interface
            XTextViewCursorSupplier xViewCursorSupplier =
                    (XTextViewCursorSupplier) UnoRuntime.queryInterface(
                    XTextViewCursorSupplier.class, xController);
            // get the cursor
            xViewCursor = xViewCursorSupplier.getViewCursor();

        } catch (Exception ex) {
            Logger.getLogger(TransliterationUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * This method set the location of the frame in the bottom of the
     * screen.
     */
    private void setBottomLocation() {
        // Get screen size
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();

        // Get the center of you screen
        int w = this.getSize().width;
        int h = this.getSize().height;
        int x = (dim.width - w) / 2;
        int y = (dim.height - h) / 2;

        // Move the window
        this.setLocation(x, dim.height - 5 * h / 4);
    }

    /**
     * @return the path
     */
    public String getPath() {
        return path;
    }

    /**
     * @param path the path to set
     */
    public void setPath(String path) {
        this.path = path;
    }

    /**
     * This method reset the variables used in transliteration and display of the
     * frame.
     */
    private void reset() {
        word = "";
        displayWord = "";
        charCount = 0;
        spaceCount = 0;
        preSpaceCount = 0;
    }
}
